﻿using Biotech.Common.Driver;
using Biotech.Common.Util;
using Biotech.Log;
using ConnectX;
using project.B12.IRepository;
using project.B12.IService;
using project.B12.Model.Enums;
using project.B12.Model.Models;
using project.B12.Model.Res;
using software.b12.api;
using software.B12.api.module;
using software.common.def;
using software.Common.MVVM;
using Software.Common.Util.AppConfig;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Drawing;
using System.IO.Compression;
using System.Text;
using System.Windows;
using static software.b12.api.B12Api;

namespace project.B12.Service
{
    public class ServiceDevice : ObservableObject, IServiceDevice
    {
        #region Model
        private AutoResetEvent _workSeq=new AutoResetEvent(false);

        private B12Api B12Api = new B12Api();

        private int PhotographErrorTimes;

        private bool _isInit = true;

        /// <summary>
        /// 需要扫描的培育仓架
        /// </summary>
        private List<int> _shelfScanNeeds = new List<int>();

        private Dictionary<int, List<int>> _noNeedScanneds = new Dictionary<int, List<int>>();

        /// <summary>
        /// 抓手上存在板子
        /// </summary>
        private bool plateExistence;

        /// <summary>
        /// 最大温度值
        /// </summary>
        private float tMax;

        /// <summary>
        /// 最小温度值
        /// </summary>
        private float tMin;

        /// <summary>
        /// 培育仓转动的间隔时间
        /// </summary>
        private int _turnSecond;

        /// <summary>
        /// 加样位置记录
        /// </summary>
        private List<int> _sampleIndexes;

        private StringBuilder _notOnlyCodeMessage { get; set; }

        private bool _isDiscontinue { get; set; }

        private bool _isOffline {  get; set; }

        public bool Disinfection { get; set; }

        public bool IsLogOut { get; set; }

        public bool IsUpdateWellPlateIDList { get; set; }

        public bool IsPhotoInterval { get; set; }

        private string _currentDoorState;
        public string CurrentDoorState
        {
            get { return _currentDoorState; }
            set { _currentDoorState = value; this.RaisePropertyChanged(); }
        }

        private string _temperature;
        public string Temperature
        {
            get { return _temperature; }
            set { _temperature = value; this.RaisePropertyChanged(); }
        }

        private string connectStatus;
        public string ConnectStatus
        {
            get { return connectStatus; }
            set
            {
                if (isConnect)
                    connectStatus = Resources.Connect;
                else
                    connectStatus = Resources.DisConnect;
                this.RaisePropertyChanged();
            }
        }

        private DeviceState _deviceState;
        public DeviceState deviceState
        {
            get { return _deviceState; }
            set
            {
                _deviceState = value;
                this.RaisePropertyChanged();
            }
        }

        private int _currentShelfIndex = 1;
        public int CurrentShelfIndex
        {
            get { return _currentShelfIndex; }
            set
            {
                _currentShelfIndex = value;
                this.RaisePropertyChanged();
            }
        }

        private bool _isTurntableEnabled;
        public bool IsTurntableEnabled
        {
            get { return _isTurntableEnabled; }
            set
            {
                _isTurntableEnabled = value;
                this.RaisePropertyChanged();
            }
        }

        public bool isConnect { get; set; }

        public bool IsOpenTest { get; set; }

        public bool IsInitEnd { get; set; }

        public bool isDestOnline { get; set; }

        public bool isBootloaderOnline { get; set; }

        public bool IsSpecialSample { get; set; }

        public ObservableCollection<Table_MonitorMes> Items64 { get; set; }
        #endregion

        #region Service
        public IConfigurationFileManagement configurationFileManagement;

        public IMICPlateMes mICPlateMes;

        public IServiceCam serviceCam { get; set; }

        public IServiceImageProcessing serviceImageProcessing { get; set; }

        public IHisRepository hisRepository { get; set; }

        public IMonitorMesRepository monitorMesRepository;

        public delegate void MessagePushEventHandler(string pMessage);

        public event MessagePushEventHandler MessagePush;
        #endregion

        public ServiceDevice(IConfigurationFileManagement _configurationFileManagement,
            IMICPlateMes _mICPlateMes,
            IServiceCam _serviceCam,
            IServiceImageProcessing _serviceImageProcessing,
            IHisRepository _hisRepository,
            IMonitorMesRepository _monitorMesRepository)
        {
            configurationFileManagement = _configurationFileManagement;
            mICPlateMes = _mICPlateMes;
            serviceCam = _serviceCam;
            serviceImageProcessing = _serviceImageProcessing;
            hisRepository = _hisRepository;
            monitorMesRepository = _monitorMesRepository;
            B12Api.DoorEvent += OpenAndCloseDoor;

            _sampleIndexes = new List<int>();
            for (int i = 1; i <= 12; i++)
            {
                if (i % 2 != 0)
                {
                    for (int j = 0; j < 8; j++)
                    {
                        int index = (i - 1) * 8 + j;
                        _sampleIndexes.Add(index);
                    }
                }
                else
                {
                    for (int j = 7; j >= 0; j--)
                    {
                        int index = (i - 1) * 8 + j;
                        _sampleIndexes.Add(index);
                    }
                }
            }
            Items64 = new ObservableCollection<Table_MonitorMes>();

            if (UtilAppConfig.ExistItem("IsInit"))
                _isInit = UtilAppConfig.GetAppConfig("IsInit") == "True" ? true : false;
            if (UtilAppConfig.ExistItem("IsOffline"))
                _isOffline= UtilAppConfig.GetAppConfig("IsOffline") == "True" ? true : false;
            if(UtilAppConfig.ExistItem("TurnNumber"))
                _turnSecond = int.Parse(UtilAppConfig.GetAppConfig("TurnNumber"));
            if (UtilAppConfig.ExistItem("IsPhotoInterval"))
                IsPhotoInterval = UtilAppConfig.GetAppConfig("IsPhotoInterval") == "True" ? true : false;
        }

        public void InitItems64()
        {
            List<Table_MonitorMes> monitorMeses = monitorMesRepository.QueryAllMonitorMes();
            for (int i = 1; i <= 4; i++)
            {
                for (int j = 1; j <= 16; j++)
                {
                    var items = monitorMeses.Where(o => o.Shelf == i && o.Index == j);
                    if (items.Count() == 0 || items == null)
                    {
                        Items64.Add(new Table_MonitorMes()
                        {
                            Shelf = i,
                            Index = j
                        });
                        continue;
                    }
                    Items64.Add(items.First());
                }
            }
            IsInitEnd = true;
        }

        public void Start()
        {
            _ = Running();
        }

        public void Refresh()
        {
            _ = ReflashTem();
            _ = ReflashTurnShelf();
        }

        /// <summary>
        /// 设备连接
        /// </summary>
        /// <returns></returns>
        public bool Connect()
        {
            try
            {
                bool ret = B12Api.Connect(20, 0);
                if (ret)
                {
                    Temperature = B12Api.GetCultureRoomTemp().ToString("F1");
                    isConnect = true;
                    deviceState = DeviceState.停止;
                    CurrentDoorState = B12Api.GetDoorState().ToString();
                }
                else
                {
                    deviceState = DeviceState.未连接;
                }
                return ret;
            }
            catch 
            {
                return false; 
            }
        }

        /// <summary>
        /// 设备重新连接
        /// </summary>
        /// <returns></returns>
        private bool ReConnection()
        {
            try
            {
                bool ret = B12Api.Connect(20, 0);
                if (ret)
                {
                    Temperature = B12Api.GetCultureRoomTemp().ToString("F1");
                    isConnect = true;
                    CurrentDoorState = B12Api.GetDoorState().ToString();
                }
                else
                {
                    deviceState = DeviceState.未连接;
                }
                return ret;
            }
            catch { return false; }
        }

        /// <summary>
        /// 转动培育仓架
        /// </summary>
        /// <param name="shelfIndex">培育仓架的位置</param>
        public void TurnShelf(int shelfIndex)
        {
            if (_isOffline||!isConnect)
                return;

            TurnCultureRoomGO(shelfIndex - 1);
            //if (_shelfScanNeeds.Contains(shelfIndex))
            //    return;
            //_shelfScanNeeds.Add(shelfIndex);
        }

        public void AddNoNeedScan(int shelfIndex, int platIndex)
        {
            if (!_noNeedScanneds.ContainsKey(shelfIndex))
            {
                _noNeedScanneds.Add(shelfIndex, new List<int>());
            }
            _noNeedScanneds[shelfIndex].Add(platIndex);
        }

        /// <summary>
        /// 开关门事件
        /// </summary>
        /// <param name="doorState"></param>
        private void OpenAndCloseDoor(DoorState doorState)
        {
            CurrentDoorState = doorState.ToString();
            LoggerFactory.Instance.CurrentLogger.LogInfo(CurrentDoorState, "", "软件");
            if (deviceState == DeviceState.初始化)
                return;
            var state = deviceState;
            if (doorState == DoorState.开门 && deviceState != DeviceState.消毒)
            {
                //_shelfScanNeeds = new List<int>();
                //_shelfScanNeeds.Add(CurrentShelfIndex);
                deviceState = DeviceState.即将暂停;
            }
            else if (doorState == DoorState.关门)
            {
                if (deviceState == DeviceState.停止)
                    deviceState = DeviceState.初始化;
                else if (deviceState == DeviceState.暂停)
                    deviceState = DeviceState.空闲;
                else
                    deviceState = state;
                IsTurntableEnabled = false;
            }
            _workSeq.Set();
        }

        /// <summary>
        /// 设备状态维护
        /// </summary>
        /// <returns></returns>
        private async Task Running()
        {
            await Task.Run(() =>
            {
                while (true)
                {
                    _workSeq.WaitOne(100);
                    if (isConnect)
                    {
                        switch (deviceState)
                        {
                            case DeviceState.停止:
                                if (B12Api.GetDoorState() == DoorState.关门)
                                    deviceState = DeviceState.初始化;
                                else
                                    MessageBox.Show(Resources.DeviceInit);
                                break;
                            case DeviceState.初始化:
                                Initialize();
                                deviceState = DeviceState.空闲;
                                break;
                            case DeviceState.空闲:
                                Work();
                                if (B12Api.GetDoorState() == DoorState.开门)
                                    deviceState = DeviceState.即将暂停;
                                else
                                    deviceState = DeviceState.空闲;
                                break;
                            case DeviceState.暂停:
                                if (B12Api.GetDoorState() == DoorState.关门)
                                {
                                    deviceState = DeviceState.空闲;
                                    _isDiscontinue = false;
                                }
                                else
                                    IsTurntableEnabled = true;
                                break;
                            case DeviceState.运行:
                                break;
                            case DeviceState.即将暂停:
                                deviceState = DeviceState.暂停;
                                break;
                            case DeviceState.消毒:
                                break;
                        }
                    }
                    //Thread.Sleep(100);
                }
            });
        }

        /// <summary>
        /// 每秒获取温度值
        /// </summary>
        /// <returns></returns>
        private async Task ReflashTem()
        {
            await Task.Run(() =>
            {
                while (true)
                {
                    try
                    {
                        if (isConnect)
                        {
                            ConnectStatus = Resources.Connect;
                            float tem = B12Api.GetCultureRoomTemp();
                            Temperature = tem.ToString("F1");
                            if (tem > tMax)
                                tMax = tem;
                            else if (tem < tMin)
                                tMin = tem;
                        }
                        else
                        {
                            ConnectStatus = Resources.DisConnect;
                            ReConnection();
                        }
                        Task.Delay(1000);
                    }
                    catch (ExcuteException ex)
                    {
                        if (ex.ErrCode == (uint)ErrCode.CONNECTX_ADAPTER_NOT_EXIST
                                    || ex.ErrCode == (uint)ErrCode.CONNECTX_TIMEOUT
                                    || ex.ErrCode == (uint)ErrCode.CONNECTX_NO_PACKET_ACK
                                    || ex.ErrCode == (uint)ErrCode.BUS_REQ_TX_FAILED)
                        {
                            isConnect = false;
                            LoggerFactory.Instance.CurrentLogger.LogInfo("设备断连", "", "软件");
                        }
                    }
                }

            });
        }

        /// <summary>
        /// 定时转动培育仓
        /// </summary>
        /// <returns></returns>
        private async Task ReflashTurnShelf()
        {
            await Task.Run(async () =>
            {
                while(true)
                {
                    if (deviceState == DeviceState.空闲 && Items64.Any(o => o.State == HoleState.Incubation))
                    {
                        TurnCultureRoomGO((CurrentShelfIndex + 2) % 4);
                    }
                    await Task.Delay(_turnSecond*1000);
                }
            });
        }

        /// <summary>
        /// 初始化
        /// </summary>
        private void Initialize()
        {
            if (IsLogOut)
                return;
            try
            {
                B12Api.Grab.GrabReset();
            }
            catch (ModuleException ex)
            {
                if(ex.ErrCode == 11750)
                {
                    //MessageBox.Show("抓手上存在")
                }
                plateExistence = true;
            }
            B12Api.SetUVLamp(false);
            B12Api.Grab.CoverReset();
            SamplerReset(2);
            CultureRoomReset();
            if (_isInit)
                ScanAllShelf();
            CloseCultureRoom();
            if (plateExistence)
            {
                ReplacePlate();
            }
            serviceCam.CloseCam();
            B12Api.Grab.LedCtrl(false);
        }

        /// <summary>
        /// 放回抓手上的板
        /// </summary>
        private void ReplacePlate()
        {
            var samplings = Items64.Where(o => o.State == HoleState.SAMPLING);
            var photographs = Items64.Where(o => o.State == HoleState.Photograph);
            var currentPlate = new Table_MonitorMes();
            if (samplings.Count() == 0 && photographs.Count() == 0)
            {
                currentPlate = Items64.Where(o => o.State == HoleState.NULL).First();
                currentPlate.State = HoleState.Error;
                MessageBox.Show(string.Format("废板放置在{0}架{1}上。", currentPlate.Shelf.ToString(), currentPlate.Index.ToString()));
                PutCupBeforeInit(currentPlate);
                monitorMesRepository.UpdateMonitorMes(currentPlate);
                return;
            }
            if (samplings.Count() > 0)
            {
                currentPlate = samplings.First();
                currentPlate.State = HoleState.SampleError;
            }
            else if (photographs.Count() > 0)
            {
                currentPlate = photographs.First();
                currentPlate.State = HoleState.PhotographError;
            }
            PutCupBeforeInit(currentPlate);
            monitorMesRepository.UpdateMonitorMes(currentPlate);
        }

        #region 扫描
        /// <summary>
        /// 扫描所有架子上的条码
        /// </summary>
        private void ScanAllShelf()
        {
            _notOnlyCodeMessage = new StringBuilder();
            for (int i = 1; i < 5; i++)
            {
                TurnCultureRoomGO((i - 1 + 2) % 4);
                for (int j = 1; j < 17; j++)
                {
                    var monitorMes = Items64.Where(o => o.Shelf == i && o.Index == j).First();
                    string code = null;
                    B12Api.Grab.GoScanCode(j - 1, 2000, ref code);
                    code = code.Replace("\r\n", "").Replace("\r", "");
                    if (string.IsNullOrEmpty(monitorMes.PlateID))
                    {
                        if (string.IsNullOrEmpty(code))
                            continue;
                        else
                            AddMonitorMes(code, monitorMes);
                    }
                    else
                    {
                        if (string.IsNullOrEmpty(code))
                        {
                            monitorMes.ShutdownOrNot = true;
                            monitorMes.State = HoleState.DONE;
                        }
                        else
                        {
                            if (monitorMes.PlateID != code)
                                UpdateMonitorMes(code, monitorMes);
                            else
                                monitorMes.ShutdownOrNot = true;
                        }
                    }
                }
            }
            PointOutCodes();
        }

        private void AddMonitorMes(string code, Table_MonitorMes monitorMes)
        {
            if (CheckCodeUniqueness(code, monitorMes))
            {
                MessageBox.Show("当前Code重复！");
                return;
            }
            monitorMes.PlateID = code;
            monitorMes.PlateType = code;
            monitorMes.State = HoleState.Free;

            monitorMesRepository.AddMonitorMes(monitorMes);
        }

        private void UpdateMonitorMes(string code, Table_MonitorMes monitorMes)
        {
            if (CheckCodeUniqueness(code, monitorMes))
            {
                MessageBox.Show("当前Code重复！");
                return;
            }
            monitorMes.PlateID = code;
            monitorMes.PlateType = code;
            monitorMes.State = HoleState.Free;

            monitorMesRepository.UpdateMonitorMes(monitorMes);
        }

        /// <summary>
        /// 检查Code的唯一性
        /// </summary>
        /// <param name="code"></param>
        /// <param name="monitorMes"></param>
        /// <returns>true表示Code重复</returns>
        private bool CheckCodeUniqueness(string code, Table_MonitorMes monitorMes)
        {
            var temp = Items64.Where(o => o.PlateID == code).ToList();

            if (temp.Count == 0 || temp == null)
            {
                LoggerFactory.Instance.CurrentLogger.LogInfo($"{code}与{monitorMes.Shelf}架{monitorMes.Index}重复");
                return false;
            }
            var originalMes = temp.First();
            _notOnlyCodeMessage.Append($"[{monitorMes.Shelf},{monitorMes.Index}]与[{originalMes.Shelf},{originalMes.Index}]重复");
            _notOnlyCodeMessage.Append("\r\n");
            return true;
        }

        private void PointOutCodes()
        {
            if (_notOnlyCodeMessage.Length == 0)
                return;

            _notOnlyCodeMessage.Append("以上位置存在Code码重复，请重新放置！");
            MessageBox.Show(_notOnlyCodeMessage.ToString());
        }
        #endregion

        private void PutCupBeforeInit(Table_MonitorMes monitorMes)
        {
            if (!isConnect)
                return;
            try
            {
                //盖盖子
                B12Api.Grab.GrabLoadCover();
            }
            catch (Exception ex)
            {
            }
            //移动培育仓
            TurnCultureRoomGO((monitorMes.Shelf - 1 + 2) % 4);
            OpenCultureRoom();
            //放回药敏板 
            B12Api.Grab.GrabPutCup(monitorMes.Index - 1);
            CloseCultureRoom();
        }

        /// <summary>
        /// 设备运行
        /// </summary>
        private void Work()
        {
            try
            {
                if (IsOpenTest)
                {
                    Test();
                    return;
                }

                if (IsSpecialSample)
                    return;

                if (_shelfScanNeeds.Count > 0 && B12Api.GetDoorState() == DoorState.关门 && _isInit)
                {
                    ScanShelf();
                    return;
                }

                var waitingForSamples = Items64.Where(o => o.State == HoleState.WaitingForSample).ToList();
                if (waitingForSamples.Count > 0 && waitingForSamples != null)
                {
                    deviceState = DeviceState.运行;
                    var waitingForSample = waitingForSamples.OrderBy(o => o.LoadTime).ToList().First();
                    Sample(waitingForSample);
                    return;
                }

                var waitingForPhotos = Items64.Where(I => I.State == HoleState.WaitingForPhotograph).ToList();
                if (waitingForPhotos != null && waitingForPhotos.Count > 0)
                {
                    if (PhotographErrorTimes > 3)
                    {
                        MessagePush?.Invoke("相机异常，取消拍照");
                        return;
                    }
                    deviceState = DeviceState.运行;
                    var waitingForPhoto = waitingForPhotos.OrderBy(I => I.AddSampleTime).ToList().First();
                    Photo(waitingForPhoto);
                    return;
                }

                var intervalPhotos = Items64.Where(o => o.IsPhoto == true).ToList();
                if (intervalPhotos != null && intervalPhotos.Count > 0)
                {
                    if (PhotographErrorTimes > 3)
                    {
                        MessagePush?.Invoke("相机异常，取消拍照");
                        return;
                    }
                    deviceState = DeviceState.运行;
                    var intervalPhoto = intervalPhotos.OrderBy(I => I.AddSampleTime).ToList().First();

                    if (GetCup(intervalPhoto))
                    {
                        PhotoInterval(intervalPhoto, intervalPhoto.PhotoIntervalTime * intervalPhoto.PhotoCount);
                        PutCup(intervalPhoto);
                        intervalPhoto.IsPhoto = false;
                    }
                    return;
                }

                //if (B12Api.GetDoorState() == DoorState.开门)
                //    deviceState = DeviceState.即将暂停;
                //else
                //    deviceState = DeviceState.空闲;
            }
            catch (Exception ex)
            {
                LoggerFactory.Instance.CurrentLogger.LogInfo(ex.ToString(),"", "软件");
            }
        }

        private void Test()
        {
            var waitingForSamples = Items64.Where(o => o.State == HoleState.WaitingForSample).ToList();
            if (waitingForSamples.Count > 0 && waitingForSamples != null)
            {
                deviceState = DeviceState.运行;
                var waitingForSample = waitingForSamples.OrderBy(o => o.LoadTime).ToList().First();
                Sample(waitingForSample);
            }

            var waitingForPhotos = Items64.Where(I => I.State == HoleState.WaitingForPhotograph).ToList();
            if (waitingForPhotos != null && waitingForPhotos.Count > 0)
            {
                if (PhotographErrorTimes > 3)
                {
                    MessagePush?.Invoke("相机异常，取消拍照");
                    return;
                }
                deviceState = DeviceState.运行;
                var waitingForPhoto = waitingForPhotos.OrderBy(I => I.AddSampleTime).ToList().First();
                Photo(waitingForPhoto);
            }
        }

        /// <summary>
        /// 加样
        /// </summary>
        /// <param name="waitingForSample">待加样的药敏板</param>
        private void Sample(Table_MonitorMes waitingForSample)
        {
            var mf = mICPlateMes.microplateAntibioticConcentrationMes.Find(p => p.name == waitingForSample.PlateType);
            if (mf == null)
            {
                throw new Exception("配置文件错误");
            }
            int volume = 0;
            int volumeCount = 0;
            if(int.TryParse(mf.Volume,out volume))
            {
                volumeCount = volume / 50;
            }

            //药敏板状态改为加样中
            waitingForSample.GoToAddSample();
            monitorMesRepository.UpdateMonitorMes(waitingForSample);
            if (!GetCup(waitingForSample))
            {
                waitingForSample.State=HoleState.SampleError;
                monitorMesRepository.UpdateMonitorMes(waitingForSample);
                return;
            } 

            foreach(var index in _sampleIndexes)
            {
                if (_isDiscontinue)
                    break;
                GrabAddSample(waitingForSample.LorR, index, volumeCount);
            }

            SamplerReset(waitingForSample.LorR);
            //间隔拍照
            if(IsPhotoInterval&& waitingForSample.PhotoIntervalTime>0)
            {
                B12Api.Grab.GrabGoSafePos();
                PhotoInterval(waitingForSample,0);
            }
            PutCup(waitingForSample);
            if (_isDiscontinue)
            {
                LoggerFactory.Instance.CurrentLogger.LogInfo("中止加样", "", "软件");
                TurnCultureRoomGO(waitingForSample.Shelf - 1);
                deviceState = DeviceState.暂停;
                return;
            }
            LoggerFactory.Instance.CurrentLogger.LogInfo("加样结束", "", "软件");
            //药敏板状态改为孵育中
            waitingForSample.AddSampleComplete();
            monitorMesRepository.UpdateMonitorMes(waitingForSample);
            //if (deviceState == DeviceState.即将暂停)
            //{
            //    deviceState = DeviceState.暂停;
            //}
            //else
            //    deviceState = DeviceState.空闲;
        }

        /// <summary>
        /// 特殊加样第一次加样
        /// </summary>
        /// <param name="monitorMes"></param>
        public void SampleSpecialFirst(Table_MonitorMes monitorMes)
        {
            while (true)
            {
                if (deviceState == DeviceState.空闲)
                    break;
            }
            deviceState = DeviceState.运行;
            if (!GetCup(monitorMes))
            {
                monitorMes.State = HoleState.SampleError;
                monitorMesRepository.UpdateMonitorMes(monitorMes);
                return;
            }
            //药敏板状态改为加样中
            monitorMes.GoToAddSample();
            monitorMesRepository.UpdateMonitorMes(monitorMes);
            LoggerFactory.Instance.CurrentLogger.LogInfo(monitorMes.PlateID + "申请加样", "", "软件");
        }

        /// <summary>
        /// 特殊加样
        /// </summary>
        /// <param name="lorR"></param>
        public void SampleSpecial(int lorR, List<int> samples,int volumeCount, Table_MonitorMes monitorMes)
        {
            monitorMesRepository.UpdateMonitorMes(monitorMes);
            foreach(var index in samples)
            {
                if (_isDiscontinue)
                {
                    FinishSampleSpacial(monitorMes);
                    monitorMes.State = HoleState.SampleError;
                    monitorMesRepository.UpdateMonitorMes(monitorMes);
                    return;
                }
                GrabAddSample(lorR, index,volumeCount);
            }
            SamplerReset(monitorMes.LorR);
        }

        /// <summary>
        /// 特殊加样完成
        /// </summary>
        /// <param name="monitorMes"></param>
        public void FinishSampleSpacial(Table_MonitorMes monitorMes)
        {
            try
            {
                if (IsPhotoInterval && monitorMes.PhotoIntervalTime > 0)
                {
                    B12Api.Grab.GrabGoSafePos();
                    PhotoInterval(monitorMes, 0);
                }
                PutCup(monitorMes);
                SamplerReset(monitorMes.LorR);
                IsSpecialSample = false;
                LoggerFactory.Instance.CurrentLogger.LogInfo("加样结束", "", "软件");
                //药敏板状态改为孵育中
                monitorMes.AddSampleComplete();
                monitorMesRepository.UpdateMonitorMes(monitorMes);
                if (deviceState == DeviceState.即将暂停)
                {
                    deviceState = DeviceState.暂停;
                }
                else
                    deviceState = DeviceState.空闲;
            }
            catch(Exception ex)
            {
                LoggerFactory.Instance.CurrentLogger.LogInfo(ex.ToString(), "", "软件");
            }
            
        }

        /// <summary>
        /// 拍照
        /// </summary>
        /// <param name="waitingForSample"></param>
        private void Photo(Table_MonitorMes waitingForPhoto)
        {
            var startTime = DateTime.Now;
            B12Api.Grab.LedCtrl(true);
            if (!GetCup(waitingForPhoto))
            {
                waitingForPhoto.State = HoleState.PhotographError;
                monitorMesRepository.UpdateMonitorMes(waitingForPhoto);
                return;
            }
                
            //药敏板状态改为拍照中
            waitingForPhoto.GoToPhoto();
            monitorMesRepository.UpdateMonitorMes(waitingForPhoto);

            string name = waitingForPhoto.SampleID + "&" + waitingForPhoto.PlateID;
            string savedPath = Path.Combine("Image", name);
            if (!serviceCam.OpenCam(true))
            {
                PhotographErrorTimes++;
                MessagePush?.Invoke("相机打开失败");
                PutCup(waitingForPhoto);
                waitingForPhoto.PhotoError();
                monitorMesRepository.UpdateMonitorMes(waitingForPhoto);
                return;
            }
            
            SaveRule(savedPath, waitingForPhoto.PlateType);
            PhotographErrorTimes = 0;
            int[] lujin = new int[6] { 3, 4, 5, 2, 1, 0 };
            for (int i = 0; i < 6; i++)
            {
                B12Api.Grab.GoPhotograph(lujin[i]);
                Thread.Sleep(20);
                Bitmap bitmap = serviceCam.TakeSinglePic();
                serviceImageProcessing.CutAndSave(savedPath, bitmap, lujin[i], waitingForPhoto.PlateType);
            }
            var retClose = serviceCam.CloseCam();
            if (!retClose)
            {
                PhotographErrorTimes++;
                MessagePush?.Invoke("相机关闭失败");
                LoggerFactory.Instance.CurrentLogger.LogInfo("相机关闭失败", "", "软件");
            }
            B12Api.Grab.LedCtrl(false);
            serviceImageProcessing.CombinImageAndSave("Jigsaw", name, 8, 12, waitingForPhoto.PlateType);
            serviceImageProcessing.DelPics(savedPath);
            monitorMesRepository.UpdateMonitorMes(waitingForPhoto);
            SaveToDB(waitingForPhoto);
            MessagePush?.Invoke($"药敏板：“{waitingForPhoto.SampleID}”\n拍摄完成");
            PutCup(waitingForPhoto);
            waitingForPhoto.PhotoComplete();
            monitorMesRepository.UpdateMonitorMes(waitingForPhoto);
            //IsUpdateWellPlateIDList = true;
            //waitingForPhoto.IsReport = true;
            //if (deviceState == DeviceState.即将暂停)
            //    deviceState = DeviceState.暂停;
            //else
            //    deviceState = DeviceState.空闲;
        }

        /// <summary>
        /// 间隔拍照
        /// </summary>
        /// <param name="monitorMes"></param>
        /// <param name="time">间隔的时间</param>
        private void PhotoInterval(Table_MonitorMes monitorMes,int time)
        {
            monitorMes.PhotoCount++;
            B12Api.Grab.LedCtrl(true);
            string name = monitorMes.SampleID + "&" + monitorMes.PlateID+$"-{time}h";
            string savedPath = Path.Combine("Image", name);
            if (serviceCam.OpenCam(true))
            {
                SaveRule(savedPath, monitorMes.PlateType);
                PhotographErrorTimes = 0;
                int[] lujin = new int[6] { 3, 4, 5, 2, 1, 0 };
                for (int i = 0; i < 6; i++)
                {
                    B12Api.Grab.GoPhotograph(lujin[i]);
                    Thread.Sleep(20);
                    Bitmap bitmap = serviceCam.TakeSinglePic();
                    serviceImageProcessing.CutAndSave(savedPath, bitmap, lujin[i], monitorMes.PlateType);
                }
                var retClose = serviceCam.CloseCam();
                if (!retClose)
                {
                    PhotographErrorTimes++;
                    MessagePush?.Invoke("相机关闭失败");
                    LoggerFactory.Instance.CurrentLogger.LogInfo("相机关闭失败", "", "软件");
                }
                B12Api.Grab.LedCtrl(false);
                serviceImageProcessing.CombinImageAndSave("Jigsaw", name, 8, 12, monitorMes.PlateType);
                serviceImageProcessing.DelPics(savedPath);
                SaveToDB(monitorMes);
                MessagePush?.Invoke($"药敏板：{monitorMes.SampleID}{time}h”\n拍摄完成");
            }
            else
            {
                PhotographErrorTimes++;
                B12Api.Grab.LedCtrl(false);
                MessagePush?.Invoke("相机打开失败");
                monitorMes.PhotoError();
            }
        }

        /// <summary>
        /// 压缩
        /// </summary>
        private void Zip()
        {
            string sourceFolder = AppDomain.CurrentDomain.BaseDirectory + @"Image";
            string time = DateTime.Now.ToString("yyyyMMdd");
            StringBuilder str = new StringBuilder(time);
            string outputZip = time + ".zip";
            ZipFile.CreateFromDirectory(sourceFolder, outputZip);
        }

        /// <summary>
        /// 保存项目模版到对应的文件夹
        /// </summary>
        /// <param name="savePath">保存路径</param>
        /// <param name="plateType">项目类型</param>
        /// <exception cref="Exception"></exception>
        private void SaveRule(string savePath, string plateType)
        {
            if (!Directory.Exists(savePath))
            {
                DirectoryInfo dirInfo = new DirectoryInfo(savePath);
                dirInfo.Create();
            }

            var mf = mICPlateMes.microplateAntibioticConcentrationMes.Find(p => p.name == plateType);
            if (mf == null)
            {
                throw new Exception("配置文件错误");
            }
            DirectoryInfo folder = new DirectoryInfo("conf");
            string direc = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, folder.Name);
            string plateFile = plateType + ".xlsx";
            string[] files = Directory.GetFiles(direc, plateFile, SearchOption.TopDirectoryOnly);

            string sourceFile = null;
            if (files.Length > 0)
                sourceFile = files[0];
            else
                return;
            string targetPath = Path.Combine(savePath, plateFile);
            File.Copy(sourceFile, targetPath, overwrite: true);
        }

        /// <summary>
        /// 保存到 Table_His 数据库中
        /// </summary>
        private void SaveToDB(Table_MonitorMes waitingForPhoto)
        {
            var history = hisRepository.QueryHisByPlateName(waitingForPhoto.PlateID,waitingForPhoto.SampleID);
            Table_His his = new Table_His
            {
                PlateName = waitingForPhoto.PlateID,
                PlateType = waitingForPhoto.PlateType,
                BacterialName = waitingForPhoto.SampleType,
                BacterialID = waitingForPhoto.SampleID,
                LoadTime = (DateTime)waitingForPhoto.LoadTime,
                IsSpecialSample = waitingForPhoto.IsSpecialSample,
                SpecialSampleTypes = waitingForPhoto.SpecialSampleTypes,
                Tmax = tMax,
                Tmin = tMin,
                ShutdownOrNot = waitingForPhoto.ShutdownOrNot,
                PhotographyTime = DateTime.Now
            };
            if (waitingForPhoto.IsSpecialSample)
            {
                his.IsSpecialSample = waitingForPhoto.IsSpecialSample;
                his.SpecialSampleTypes = waitingForPhoto.SpecialSampleTypes;
            }
            IsUpdateWellPlateIDList = true;
            waitingForPhoto.IsReport = true;
            if (history==null|| history.Count==0)
            {
                hisRepository.AddNewHis(his);
                return;
            }

            hisRepository.UpdateHis(his);
        }

        /// <summary>
        /// 中止操作
        /// </summary>
        public void DiscontinueDevice()
        {
            _isDiscontinue = true;  
            IsSpecialSample = false;
        }

        /// <summary>
        /// 拿取药敏板
        /// </summary>
        private bool GetCup(Table_MonitorMes monitorMes)
        {
            try
            {
                //移动培育仓
                TurnCultureRoomGO((monitorMes.Shelf - 1 + 2) % 4);
                OpenCultureRoom();
                //拿药敏板
                B12Api.Grab.GrabGetCup(monitorMes.Index - 1);
                LoggerFactory.Instance.CurrentLogger.LogInfo($"取板：第{monitorMes.Shelf}架{monitorMes.Index}", "", "软件");
                CloseCultureRoom();
                //开盖
                B12Api.Grab.GrabUnloadCover();
                LoggerFactory.Instance.CurrentLogger.LogInfo("开盖", "", "软件");
                return true;
            }
            catch
            {
                MessageBox.Show("药敏板拿取有误，请检查！");
                LoggerFactory.Instance.CurrentLogger.LogInfo($"第{monitorMes.Shelf}架第{monitorMes.Index}位的药敏板拿取有误");
                CloseCultureRoom();
                return false;
            }
        }

        /// <summary>
        /// 放回药敏板
        /// </summary>
        /// <param name="waitingForPhoto"></param>
        private void PutCup(Table_MonitorMes monitorMes)
        {
            try
            {
                //盖盖子
                B12Api.Grab.GrabLoadCover();
                LoggerFactory.Instance.CurrentLogger.LogInfo("放盖", "", "软件");
                //移动培育仓
                //TurnCultureRoomGO((monitorMes.Shelf - 1 + 2) % 4);
                OpenCultureRoom();
                //放回药敏板
                B12Api.Grab.GrabPutCup(monitorMes.Index - 1);
                LoggerFactory.Instance.CurrentLogger.LogInfo($"放板：第{monitorMes.Shelf}架{monitorMes.Index}", "", "软件");
                CloseCultureRoom();
            }
            catch(Exception ex)
            {
                MessageBox.Show("药敏板放回有误，请检查！");
                CloseCultureRoom();
                LoggerFactory.Instance.CurrentLogger.LogInfo(ex.ToString(), "", "软件");
            }
        }



        /// <summary>
        /// 开始消毒，15分钟转一架
        /// </summary>
        /// <param name="time">小时</param>
        public async void StartDisinfection(int time)
        {
            try
            {
                Disinfection = true;
                deviceState = DeviceState.消毒;
                int disinfectionCount = time * 4;//一小时4次
                for (int i = 0; i < disinfectionCount; i++)
                {
                    if (!Disinfection)
                        return;
                    int shelfIndex = 0;
                    if (i > 4)
                        shelfIndex = i - 4;
                    else
                        shelfIndex = i;
                    TurnShelf(shelfIndex);
                    B12Api.SetUVLamp(true);
                    await Task.Delay(15 * 60 * 1000);
                }
                MessageBox.Show(Resources.DisinfectionDone);
                B12Api.SetUVLamp(false);
                Initialize();
                Disinfection = false;
            }
            catch(Exception ex)
            {
                LoggerFactory.Instance.CurrentLogger.LogInfo(ex.ToString(), "", "软件");
            }
        }

        /// <summary>
        /// 停止消毒
        /// </summary>
        /// <returns></returns>
        public bool StopDisinfection()
        {
            try
            {
                if (B12Api.GetDoorState() == DoorState.开门)
                {
                    MessageBox.Show("请关门再进行操作。");
                    return false;
                }
                //Initialize();
                B12Api.SetUVLamp(false);
                Disinfection = false;
                deviceState = DeviceState.初始化;
                return true;
            }
            catch(Exception ex)
            {
                LoggerFactory.Instance.CurrentLogger.LogInfo(ex.ToString(), "", "软件");
                return false;
            }
        }

        /// <summary>
        /// 扫描培育仓架
        /// </summary>
        private void ScanShelf()
        {
            deviceState = DeviceState.运行;
            _notOnlyCodeMessage = new StringBuilder();
            for (int i = 0; i < _shelfScanNeeds.Count(); i++)
            {
                int shelfIndex = _shelfScanNeeds[i];
                if (_noNeedScanneds.ContainsKey(shelfIndex))
                {
                    for (int j = 1; j < 17; j++)
                    {
                        if (_noNeedScanneds[shelfIndex].Contains(j))
                            continue;
                        var plates = Items64.Where(o => o.Shelf == _shelfScanNeeds[i] && o.Index == j && o.State == HoleState.NULL);
                        if (plates == null || plates.Count() == 0)
                            continue;
                        var plate = plates.First();
                        Scan(plate, j - 1);
                    }
                    continue;
                }
                //全扫
                for (int j = 1; j < 17; j++)
                {
                    var plates = Items64.Where(o => o.Shelf == _shelfScanNeeds[i] && o.Index == j && o.State == HoleState.NULL);
                    if (plates.Count() == 0 || plates == null)
                        continue;
                    var plate = plates.First();
                    Scan(plate, j - 1);
                }
            }
            CloseCultureRoom();
            PointOutCodes();
            _shelfScanNeeds = new List<int>();
            //if (deviceState == DeviceState.即将暂停)
            //{
            //    deviceState = DeviceState.暂停;
            //}
            //else
            //    deviceState = DeviceState.空闲;
        }

        private void Scan(Table_MonitorMes plate, int index)
        {
            TurnCultureRoomGO((plate.Shelf - 1 + 2) % 4);
            OpenCultureRoom();

            string code = null;
            B12Api.Grab.GoScanCode(index, 2000, ref code);
            code = code.Replace("\r\n", "").Replace("\r", "");
            if (string.IsNullOrEmpty(code))
                return;
            if (CheckCodeUniqueness(code, plate))
                return;
            plate.PlateID = code;
            plate.PlateType = code;
            plate.State = HoleState.Free;
            monitorMesRepository.AddMonitorMes(plate);
        }

        /// <summary>
        /// 培育仓复位
        /// </summary>
        public void CultureRoomReset()
        {
            try
            {
                B12Api.CultureRoom.ResetG();
                B12Api.CultureRoom.ResetD();
                CurrentShelfIndex = 1;
            }
            catch(Exception ex)
            {
                LoggerFactory.Instance.CurrentLogger.LogInfo(ex.ToString(),"","软件");
            }
        }

        /// <summary>
        /// 加样复位
        /// </summary>
        /// <param name="lorR">0表示左加样，2表示全部复位</param>
        public async void  SamplerReset(int lorR)
        {
            try
            {
                await Task.Run(() =>
                {
                    switch (lorR)
                    {
                        case 0:
                            B12Api.Sampler.Sampler1Reset(-50, 500);
                            return;
                        case 1:
                            B12Api.Sampler.Sampler2Reset(-50, 500);
                            return;
                        default:
                            B12Api.Sampler.Sampler1Reset(-50, 500);
                            B12Api.Sampler.Sampler2Reset(-50, 500);
                            return;
                    }
                });
            }
            catch(Exception ex)
            {
                LoggerFactory.Instance.CurrentLogger.LogInfo(ex.ToString(), "", "软件");
            }
        }

        /// <summary>
        /// 修改温度
        /// </summary>
        /// <param name="temp"></param>
        public void UpdateTemp(float temp)
        {
            try
            {
                B12Api.SetCultureRoomTemp(temp);
                LoggerFactory.Instance.CurrentLogger.LogInfo($"温度修改成功，当前温度为：{temp}℃", "", "软件");
            }
            catch(Exception ex)
            {
                LoggerFactory.Instance.CurrentLogger.LogInfo("温度修改失败\n" + ex.ToString(), "", "软件");
            }
        }

        /// <summary>
        /// 转动培育仓
        /// </summary>
        /// <param name="index">从0开始</param>
        public async void TurnCultureRoomGO(int index)
        {
            try
            {
                lock (this)
                {
                    B12Api.CultureRoom.GoGPos(index);
                    CurrentShelfIndex = index + 1;
                }
            }
            catch(Exception ex)
            {
                LoggerFactory.Instance.CurrentLogger.LogInfo(ex.ToString(), "", "软件");
            }
        }

        public void OpenCultureRoom()
        {
            try
            {
                B12Api.CultureRoom.OpenDoor();
            }
            catch(Exception ex)
            {
                LoggerFactory.Instance.CurrentLogger.LogInfo(ex.ToString(), "", "软件");
            }
        }

        public void CloseCultureRoom()
        {
            try
            {
                B12Api.CultureRoom.CloseDoor();
            }
            catch(Exception ex)
            {
                LoggerFactory.Instance.CurrentLogger.LogInfo(ex.ToString(), "", "软件");
            }
        }

        /// <summary>
        /// 单孔加样
        /// </summary>
        /// <param name="LorF">左右加样位</param>
        /// <param name="index">板的加样位</param>
        /// <param name="volumeCount"></param>
        private void GrabAddSample(int LorF, int index,int volumeCount)
        {
            try
            {
                if (LorF == 0)
                {
                    for (int i = 0; i < volumeCount; i++)
                    {
                        B12Api.AddSample_50(SampleAdder.L加样, index, -50, 550, 50, 50, 150);
                    }
                }
                else
                {
                    for (int i = 0; i < volumeCount; i++)
                    {
                        B12Api.AddSample_50(SampleAdder.R加样, index, -50, 550, 50, 50, 150);
                    }
                }
            }
            catch(Exception ex)
            {
                LoggerFactory.Instance.CurrentLogger.LogInfo($"{LorF}加样有误：\n"+ex.ToString(), "", "软件");
            }
        }

        private void ValidateBeforeInit()
        {
            var samplings = Items64.Where(o => o.State == HoleState.SAMPLING);
            var photographs = Items64.Where(o => o.State == HoleState.Photograph);
            if (samplings.Count() > 0)
            {
                foreach (var sampling in samplings)
                {
                    PutCupBeforeInit(sampling);
                    sampling.State = HoleState.SampleError;
                    monitorMesRepository.UpdateMonitorMes(sampling);
                }
            }
            else if (photographs.Count() > 0)
            {
                foreach (var photograph in photographs)
                {
                    PutCupBeforeInit(photograph);
                    photograph.State = HoleState.PhotographError;
                    monitorMesRepository.UpdateMonitorMes(photograph);
                }
            }
        }
    }
}
